package main

import (
	"database/sql"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"log"
	"net"
	"time"

	_ "mysql-master"
)

const (
	dbUser     = "root"
	dbPassword = "haohao"
	dbName     = "db2"
)
const (
	FrameHeader = 0xA55A
	FrameTail   = 0xCC33C33C
)

type Frame struct {
	Header       uint16
	Length       uint8
	Manufacturer uint8
	Version      uint8
	FrameType    uint8
	DeviceID     [4]byte
	Info         []byte
	Checksum     uint8
	Tail         uint32
}

type DeviceAttributes struct {
	SIMCard          string
	GroupID          uint16
	TowerInGroup     uint16
	RopeRate         uint8
	XCoordinate      float32
	YCoordinate      float32
	FrontArmLength   float32
	RearArmLength    float32
	TowerCapHeight   float32
	TowerBodyHeight  float32
	Longitude        float64
	Latitude         float64
	MaxLeftAngle     float32
	MaxRightAngle    float32
	MaxFrontDistance float32
	MaxRearDistance  float32
	MaxHeight        float32
	MaxWeight        float32
	WarningRate      uint8
	AlarmRate        uint8
	ViolationRate    uint8
}

type RealTimeData struct {
	UploadTimestamp  time.Time
	Height           uint32
	Amplitude        uint32
	Angle            int32
	Load             uint32
	SafeLoadRatio    uint8
	Torque           uint32
	CurrentWindSpeed uint32
	TiltAngleX       int32
	TiltAngleY       int32
	EquipmentStatus  uint32
}

type LiftingData struct {
	UploadTimestamp time.Time
	StartTimestamp  time.Time
	EndTimestamp    time.Time
	MaxLoad         uint32
	MaxTorque       uint32
	StartAngle      int32
	EndAngle        int32
	StartAmplitude  uint32
	EndAmplitude    uint32
	MaxHeight       uint32
	MinHeight       uint32
	MaxWindSpeed    uint32
	TiltAngleX      int32
	TiltAngleY      int32
	EquipmentStatus uint32
}

func parseFrame(data []byte) (*Frame, error) {
	if len(data) < 14 { // Minimum frame length
		return nil, fmt.Errorf("数据太短")
	}

	header := binary.BigEndian.Uint16(data[0:2])
	if header != FrameHeader {
		return nil, fmt.Errorf("无效的帧头: %x", header)
	}

	length := data[2]
	expectedLength := int(length) // Length includes the entire frame length
	if len(data) != expectedLength {
		return nil, fmt.Errorf("无效的数据长度: 期望 %d, 实际 %d", expectedLength, len(data))
	}

	tail := binary.BigEndian.Uint32(data[len(data)-4:])
	if tail != FrameTail {
		return nil, fmt.Errorf("无效的帧尾: %x", tail)
	}

	frame := &Frame{
		Header:       header,
		Length:       length,
		Manufacturer: data[3],
		Version:      data[4],
		FrameType:    data[5],
	}
	copy(frame.DeviceID[:], data[6:10])
	frame.Info = data[10 : len(data)-5]
	frame.Checksum = data[len(data)-5]
	frame.Tail = tail

	return frame, nil
}

func parseTimestamp(info []byte) (time.Time, error) {
	if len(info) < 4 {
		return time.Time{}, fmt.Errorf("信息段太短，无法解析时间戳")
	}
	timestamp := binary.BigEndian.Uint32(info[:4])
	return time.Unix(int64(timestamp), 0), nil
}

func parseDeviceAttributes(info []byte) (*DeviceAttributes, error) {
	if len(info) < 88 {
		return nil, fmt.Errorf("信息段太短，无法解析设备属性")
	}

	attributes := &DeviceAttributes{
		SIMCard:          string(info[:20]),
		GroupID:          binary.BigEndian.Uint16(info[20:22]),
		TowerInGroup:     binary.BigEndian.Uint16(info[22:24]),
		RopeRate:         info[24],
		XCoordinate:      float32(binary.BigEndian.Uint32(info[25:29])) / 100,
		YCoordinate:      float32(binary.BigEndian.Uint32(info[29:33])) / 100,
		FrontArmLength:   float32(binary.BigEndian.Uint32(info[33:37])) / 100,
		RearArmLength:    float32(binary.BigEndian.Uint32(info[37:41])) / 100,
		TowerCapHeight:   float32(binary.BigEndian.Uint32(info[41:45])) / 100,
		TowerBodyHeight:  float32(binary.BigEndian.Uint32(info[45:49])) / 100,
		Longitude:        float64(binary.BigEndian.Uint32(info[49:53])) / 1000000,
		Latitude:         float64(binary.BigEndian.Uint32(info[53:57])) / 1000000,
		MaxLeftAngle:     float32(binary.BigEndian.Uint32(info[57:61])) / 100,
		MaxRightAngle:    float32(binary.BigEndian.Uint32(info[61:65])) / 100,
		MaxFrontDistance: float32(binary.BigEndian.Uint32(info[65:69])) / 100,
		MaxRearDistance:  float32(binary.BigEndian.Uint32(info[69:73])) / 100,
		MaxHeight:        float32(binary.BigEndian.Uint32(info[73:77])) / 100,
		MaxWeight:        float32(binary.BigEndian.Uint32(info[77:81])) / 100,
		WarningRate:      info[81],
		AlarmRate:        info[82],
		ViolationRate:    info[83],
	}

	return attributes, nil
}

func parseRealTimeData(info []byte) (*RealTimeData, error) {
	if len(info) < 46 {
		return nil, fmt.Errorf("信息段太短，无法解析实时数据")
	}

	timestamp := binary.BigEndian.Uint32(info[:4])
	height := binary.BigEndian.Uint32(info[4:8])
	amplitude := binary.BigEndian.Uint32(info[8:12])
	angle := int32(binary.BigEndian.Uint32(info[12:16]))
	load := binary.BigEndian.Uint32(info[16:20])
	safeLoadRatio := info[20]
	torque := binary.BigEndian.Uint32(info[21:25])
	windSpeed := binary.BigEndian.Uint32(info[25:29])
	tiltAngleX := int32(binary.BigEndian.Uint32(info[29:33]))
	tiltAngleY := int32(binary.BigEndian.Uint32(info[33:37]))
	equipmentStatus := binary.BigEndian.Uint32(info[37:41])

	return &RealTimeData{
		UploadTimestamp:  time.Unix(int64(timestamp), 0),
		Height:           height,
		Amplitude:        amplitude,
		Angle:            angle,
		Load:             load,
		SafeLoadRatio:    safeLoadRatio,
		Torque:           torque,
		CurrentWindSpeed: windSpeed,
		TiltAngleX:       tiltAngleX,
		TiltAngleY:       tiltAngleY,
		EquipmentStatus:  equipmentStatus,
	}, nil
}

func parseLiftingData(info []byte) (*LiftingData, error) {
	if len(info) < 78 {
		return nil, fmt.Errorf("信息段太短，无法解析吊装数据")
	}

	liftingData := &LiftingData{
		UploadTimestamp: time.Unix(int64(binary.BigEndian.Uint32(info[:4])), 0),
		StartTimestamp:  time.Unix(int64(binary.BigEndian.Uint32(info[4:8])), 0),
		EndTimestamp:    time.Unix(int64(binary.BigEndian.Uint32(info[8:12])), 0),
		MaxLoad:         binary.BigEndian.Uint32(info[12:16]),
		MaxTorque:       binary.BigEndian.Uint32(info[16:20]),
		StartAngle:      int32(binary.BigEndian.Uint32(info[20:24])),
		EndAngle:        int32(binary.BigEndian.Uint32(info[24:28])),
		StartAmplitude:  binary.BigEndian.Uint32(info[28:32]),
		EndAmplitude:    binary.BigEndian.Uint32(info[32:36]),
		MaxHeight:       binary.BigEndian.Uint32(info[36:40]),
		MinHeight:       binary.BigEndian.Uint32(info[40:44]),
		MaxWindSpeed:    binary.BigEndian.Uint32(info[44:48]),
		TiltAngleX:      int32(binary.BigEndian.Uint32(info[48:52])),
		TiltAngleY:      int32(binary.BigEndian.Uint32(info[52:56])),
		EquipmentStatus: binary.BigEndian.Uint32(info[56:60]),
	}

	return liftingData, nil
}

func saveDeviceAttributes(db *sql.DB, attributes *DeviceAttributes) error {
	query := `
		INSERT INTO device_attributes (
			sim_card, group_id, tower_in_group, rope_rate, x_coordinate, y_coordinate,
			front_arm_length, rear_arm_length, tower_cap_height, tower_body_height,
			longitude, latitude, max_left_angle, max_right_angle, max_front_distance,
			max_rear_distance, max_height, max_weight, warning_rate, alarm_rate,
			violation_rate
		) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
	`
	_, err := db.Exec(query,
		attributes.SIMCard, attributes.GroupID, attributes.TowerInGroup, attributes.RopeRate,
		attributes.XCoordinate, attributes.YCoordinate, attributes.FrontArmLength, attributes.RearArmLength,
		attributes.TowerCapHeight, attributes.TowerBodyHeight, attributes.Longitude, attributes.Latitude,
		attributes.MaxLeftAngle, attributes.MaxRightAngle, attributes.MaxFrontDistance, attributes.MaxRearDistance,
		attributes.MaxHeight, attributes.MaxWeight, attributes.WarningRate, attributes.AlarmRate, attributes.ViolationRate,
	)
	return err
}
func savetimestamp(db *sql.DB, t time.Time) error {
	query := `
	INSERT INTO time_stamp(time) VALUES (?)`
	_, err := db.Exec(query, t)
	return err
}
func saveRealTimeData(db *sql.DB, data *RealTimeData) error {
	query := `
		INSERT INTO real_time_data (
			upload_timestamp, height, amplitude, angle, load1, safe_load_ratio,
			torque, current_wind_speed, tilt_angle_x, tilt_angle_y, equipment_status
		) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
	`
	_, err := db.Exec(query,
		data.UploadTimestamp, data.Height, data.Amplitude, data.Angle, data.Load,
		data.SafeLoadRatio, data.Torque, data.CurrentWindSpeed, data.TiltAngleX, data.TiltAngleY,
		data.EquipmentStatus,
	)
	return err
}

func saveLiftingData(db *sql.DB, data *LiftingData) error {
	query := `
		INSERT INTO lifting_data (
			upload_timestamp, start_timestamp, end_timestamp, max_load, max_torque,
			start_angle, end_angle, start_amplitude, end_amplitude, max_height,
			min_height, max_wind_speed, tilt_angle_x, tilt_angle_y, equipment_status
		) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
	`
	_, err := db.Exec(query,
		data.UploadTimestamp, data.StartTimestamp, data.EndTimestamp, data.MaxLoad, data.MaxTorque,
		data.StartAngle, data.EndAngle, data.StartAmplitude, data.EndAmplitude, data.MaxHeight,
		data.MinHeight, data.MaxWindSpeed, data.TiltAngleX, data.TiltAngleY, data.EquipmentStatus,
	)
	return err
}

func handleClient(conn net.Conn, db *sql.DB) {
	defer conn.Close()

	for {
		// 从客户端读取
		buffer := make([]byte, 1024)
		n, err := conn.Read(buffer)
		if err != nil {
			log.Println("读取数据失败:", err)
			break
		}

		// 输出从客户端接收到的数据
		fmt.Printf("收到客户端数据: %s\n", hex.EncodeToString(buffer[:n]))

		// 解析数据
		frame, err := parseFrame(buffer[:n])
		if err != nil {
			log.Println("解析数据失败:", err)
			continue
		}

		// 打印解析后的数据帧信息
		fmt.Printf("帧头: 0x%x\n", frame.Header)
		fmt.Printf("长度: %d\n", frame.Length)
		fmt.Printf("厂家编号: 0x%x\n", frame.Manufacturer)
		fmt.Printf("协议版本: 0x%x\n", frame.Version)
		fmt.Printf("帧类型: 0x%x\n", frame.FrameType)
		fmt.Printf("设备编号: 0x%x\n", frame.DeviceID)
		fmt.Printf("帧尾: 0x%x\n", frame.Tail)

		// 根据帧类型处理数据
		switch frame.FrameType {
		case 0x00: // 设备注册请求帧
			timestamp, err := parseTimestamp(frame.Info)
			if err != nil {
				log.Println("解析时间戳失败:", err)
				continue
			} else {
				fmt.Printf("解析的时间戳: %s\n", timestamp.Format(time.RFC3339))
				err = savetimestamp(db, timestamp)
				if err != nil {
					log.Println("保存设备属性信息失败:", err)
				}
			}
		case 0x02: // 设备参数上报请求帧
			attributes, err := parseDeviceAttributes(frame.Info)
			if err != nil {
				log.Println("解析设备属性信息失败:", err)
			} else {
				// 打印设备属性信息
				fmt.Printf("SIM卡号: %s\n", attributes.SIMCard)
				fmt.Printf("群塔ID: %d\n", attributes.GroupID)
				fmt.Printf("塔机在群: %d\n", attributes.TowerInGroup)
				fmt.Printf("吊绳倍率: %d\n", attributes.RopeRate)
				fmt.Printf("X坐标: %.2f\n", attributes.XCoordinate)
				fmt.Printf("Y坐标: %.2f\n", attributes.YCoordinate)
				fmt.Printf("前臂长度: %.2f\n", attributes.FrontArmLength)
				fmt.Printf("后臂长度: %.2f\n", attributes.RearArmLength)
				fmt.Printf("塔帽高度: %.2f\n", attributes.TowerCapHeight)
				fmt.Printf("塔身高度: %.2f\n", attributes.TowerBodyHeight)
				fmt.Printf("经度: %.6f\n", attributes.Longitude)
				fmt.Printf("纬度: %.6f\n", attributes.Latitude)
				fmt.Printf("左转最大角度: %.2f\n", attributes.MaxLeftAngle)
				fmt.Printf("右转最大角度: %.2f\n", attributes.MaxRightAngle)
				fmt.Printf("前行最远距离: %.2f\n", attributes.MaxFrontDistance)
				fmt.Printf("回收最近距离: %.2f\n", attributes.MaxRearDistance)
				fmt.Printf("最高高度: %.2f\n", attributes.MaxHeight)
				fmt.Printf("最大起重量: %.2f\n", attributes.MaxWeight)
				fmt.Printf("预警百分比: %d\n", attributes.WarningRate)
				fmt.Printf("报警百分比: %d\n", attributes.AlarmRate)
				fmt.Printf("违章百分比: %d\n", attributes.ViolationRate)

				// 保存设备属性信息到数据库
				err = saveDeviceAttributes(db, attributes)
				if err != nil {
					log.Println("保存设备属性信息失败:", err)
				}
			}
		case 0x06: // 实时数据上报请求帧
			realTimeData, err := parseRealTimeData(frame.Info)
			if err != nil {
				log.Println("解析实时数据失败:", err)
			} else {
				// 打印实时数据
				fmt.Printf("上传时间戳: %s\n", realTimeData.UploadTimestamp.Format(time.RFC3339))
				fmt.Printf("高度: %d\n", realTimeData.Height)
				fmt.Printf("幅度: %d\n", realTimeData.Amplitude)
				fmt.Printf("转角: %.2f\n", float32(realTimeData.Angle)/100)
				fmt.Printf("载重: %d\n", realTimeData.Load)
				fmt.Printf("安全载重比: %d%%\n", realTimeData.SafeLoadRatio)
				fmt.Printf("力矩: %d\n", realTimeData.Torque)
				fmt.Printf("当前风速: %d\n", realTimeData.CurrentWindSpeed)
				fmt.Printf("倾斜角度X: %.2f\n", float32(realTimeData.TiltAngleX)/100)
				fmt.Printf("倾斜角度Y: %.2f\n", float32(realTimeData.TiltAngleY)/100)
				fmt.Printf("设备状态: %d\n", realTimeData.EquipmentStatus)

				// 保存实时数据到数据库
				err = saveRealTimeData(db, realTimeData)
				if err != nil {
					log.Println("保存实时数据失败:", err)
				}
			}
		case 0x08: // 吊装数据上报请求帧
			liftingData, err := parseLiftingData(frame.Info)
			if err != nil {
				log.Println("解析吊装数据失败:", err)
			} else {
				// 打印吊装数据
				fmt.Printf("上传时间戳: %s\n", liftingData.UploadTimestamp.Format(time.RFC3339))
				fmt.Printf("吊装开始时间戳: %s\n", liftingData.StartTimestamp.Format(time.RFC3339))
				fmt.Printf("吊装结束时间戳: %s\n", liftingData.EndTimestamp.Format(time.RFC3339))
				fmt.Printf("最大载重: %d\n", liftingData.MaxLoad)
				fmt.Printf("最大力矩: %d\n", liftingData.MaxTorque)
				fmt.Printf("开始转角: %.2f\n", float32(liftingData.StartAngle)/100)
				fmt.Printf("结束转角: %.2f\n", float32(liftingData.EndAngle)/100)
				fmt.Printf("开始幅度: %d\n", liftingData.StartAmplitude)
				fmt.Printf("结束幅度: %d\n", liftingData.EndAmplitude)
				fmt.Printf("最大起升高度: %d\n", liftingData.MaxHeight)
				fmt.Printf("最小起升高度: %d\n", liftingData.MinHeight)
				fmt.Printf("最大风速: %d\n", liftingData.MaxWindSpeed)
				fmt.Printf("倾角X: %.2f\n", float32(liftingData.TiltAngleX)/100)
				fmt.Printf("倾角Y: %.2f\n", float32(liftingData.TiltAngleY)/100)
				fmt.Printf("设备状态: %d\n", liftingData.EquipmentStatus)

				// 保存吊装数据到数据库
				err = saveLiftingData(db, liftingData)
				if err != nil {
					log.Println("保存吊装数据失败:", err)
				}
			}
		default:
			fmt.Println("未知帧类型:", frame.FrameType)
		}

		// 将接收到的数据发送回客户端
		_, err = conn.Write(buffer[:n])
		if err != nil {
			log.Println("发送数据失败:", err)
			break
		}
	}
}

var db *sql.DB

func initDB() {
	var err error
	dsn := dbUser + ":" + dbPassword + "@/" + dbName
	db, err = sql.Open("mysql", dsn)
	if err != nil {
		log.Fatalf("Error opening database: %v", err)
	}
	if err = db.Ping(); err != nil {
		log.Fatalf("Error connecting to database: %v", err)
	}
}
func main() {
	// 设置数据库连接
	//dsn := "root:haohao@tcp(127.0.0.1:5050)/db2"
	initDB()
	// db, err := sql.Open("mysql", dsn)
	// if err != nil {
	// 	log.Fatal("数据库连接失败:", err)
	// }
	// log.Fatal("数据库连接成功")
	defer db.Close()

	// 设置服务器监听的地址和端口
	listener, err := net.Listen("tcp", ":5050")
	if err != nil {
		log.Fatal("监听失败:", err)
	}
	defer listener.Close()

	fmt.Println("服务器启动，监听 5050 端口...")

	// 接受连接
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println("接受连接失败:", err)
			continue
		}

		// 为每个连接创建一个 goroutine 来处理
		go handleClient(conn, db)
	}
}
